﻿using Autofac;
using FrameWorkCore.DynamicWebApi;
using FrameWorkCore.EFCore;
using FrameWorkCore.JWT;
using FrameWorkCore.StackExchangeRedis;
using Microsoft.AspNetCore.Mvc;
using Repository.FrameWorkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace FrameWorkCore
{
    public class AutoFacModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            #region Custom injection

            #region Jwt
            builder.RegisterType<JWTAuthService>()
                 .As<IJWTAuthService>()
                 .AsImplementedInterfaces()
                 .PropertiesAutowired()
                 .InstancePerDependency();
            #endregion

            #region Redis
            builder.RegisterType<StackExchangeRedisBuilder>()
                   .PropertiesAutowired()
                   .SingleInstance();

            builder.RegisterType<RedisMultiplexer>()
                   .PropertiesAutowired()
                   .InstancePerDependency();


            #endregion

            #region The unit of work
            builder.RegisterType<UnitOfWorkManager>()
                 .As<IUnitOfWorkManager>()
                 .AsImplementedInterfaces()
                 .PropertiesAutowired()
                 .InstancePerLifetimeScope();

            builder.RegisterType<UnitOfWork>()
                .As<IUnitOfWork>()
                .AsImplementedInterfaces()
                .PropertiesAutowired()
                .InstancePerLifetimeScope();
            #endregion

            #endregion

            #region Batch injection

            var scope = typeof(IScopeDependency);
            var singleton = typeof(ISingletonDependency);
            var transient = typeof(ITransientDependency);
            var application = typeof(ApplicationService);


            #region Into the repository
            var repTypes = Assembly.Load("Repository").ExportedTypes;
            var IRep = repTypes.First(x => x.IsInterface && x.IsGenericType);
            var Rep = repTypes.First(x => x.IsClass && x.IsGenericType); ;
            if (scope.IsAssignableFrom(IRep))
                builder.RegisterGeneric(Rep).As(IRep)
                       .PropertiesAutowired()
                       .InstancePerLifetimeScope().AsSelf();
            else if (singleton.IsAssignableFrom(IRep))
                builder.RegisterGeneric(Rep).As(IRep)
                       .PropertiesAutowired()
                       .SingleInstance().AsSelf();
            else
                builder.RegisterGeneric(Rep).As(IRep)
                       .PropertiesAutowired()
                       .InstancePerDependency().AsSelf();
            #endregion


            #region Batch injection service interface
            var appTypeArray = Assembly.Load("Application").ExportedTypes;        
            var appServices = appTypeArray.Where(x => x.Name.EndsWith("Service"));
            var appTypes = appServices.Where(x => application.IsAssignableFrom(x) && x.IsClass);

            #region Generate dynamic webapi
            foreach (var appType in appTypes)
            {
                var IappType = appServices.First(x => x.Name.Contains(appType.Name) && x.IsInterface);
                var currentRegBuilder = builder.RegisterType(appType).As(IappType)
                    .AsImplementedInterfaces().PropertiesAutowired();

                if (scope.IsAssignableFrom(appType))
                    currentRegBuilder.InstancePerLifetimeScope();

                else if (singleton.IsAssignableFrom(appType))
                    currentRegBuilder.SingleInstance();
                else
                    currentRegBuilder.InstancePerDependency();

                currentRegBuilder.AsSelf();
            }
            #endregion

            #region Only injection
            var diTypes = appServices.Where(x => !application.IsAssignableFrom(x) && x.IsClass);
            foreach (var diType in diTypes)
            {
                var IdiType = appServices.FirstOrDefault(x => x.Name.Contains(diType.Name) && x.IsInterface);
                var currentRegBuilder = builder.RegisterType(diType);
                if (scope.IsAssignableFrom(diType))
                {

                    if (IdiType is null)
                        currentRegBuilder
                        .PropertiesAutowired()
                        .InstancePerLifetimeScope();
                    else
                        currentRegBuilder.As(IdiType)
                        .AsImplementedInterfaces()
                        .PropertiesAutowired()
                        .InstancePerLifetimeScope();
                }
                else if (singleton.IsAssignableFrom(diType))
                {
                    if (IdiType is null)
                        currentRegBuilder
                        .PropertiesAutowired()
                        .SingleInstance();
                    else
                        currentRegBuilder.As(IdiType)
                        .AsImplementedInterfaces()
                        .PropertiesAutowired()
                        .SingleInstance();

                }
                else
                {
                    if (IdiType is null)
                        currentRegBuilder
                        .PropertiesAutowired()
                        .InstancePerDependency();
                    else
                        currentRegBuilder.As(IdiType)
                        .AsImplementedInterfaces()
                        .PropertiesAutowired()
                        .InstancePerDependency();
                }

            }
            #endregion


            #endregion

            #endregion


            var Web = Assembly.Load("WebApi6");
            var controllerBaseType = typeof(ControllerBase);
            builder.RegisterAssemblyTypes(Web)
                   .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
                   .PropertiesAutowired();//Controller allows attributes injection
        }

    }
}
